﻿using System;
using System.Collections.Generic;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Editor.Extend;
using HK.Editor.GUIEx.Drag;
using HK.Editor.GUIEx.Property;
using HK.Editor.GUIEx.Protocol;
using HK.Editor.GUIEx.Protocol.Drawer;
using HK.Editor.GUIEx.Protocol.Pagination;
using HK.Editor.GUIEx.Styles;
using HK.Editor.Utils;
using UnityEditor;
using UnityEngine;

namespace HK.Editor.GUIEx.Drawer
{
    /// <summary>
    /// GUI绘制器 - 分页面板 - SerializedProperty
    /// </summary>
    public sealed class SpPaginationDrawer : PaginationDrawer<SerializedProperty>, ISpPaginationDrawer
    {
        
#region Create

        /// <summary>
        /// 创建GUI绘制器 - 分页面板
        /// </summary>
        /// <param name="iSelfProperty">自身Property</param>
        /// <param name="iPagination">分页设定</param>
        /// <param name="iOnSearched">检索回调</param>
        /// <param name="iElementKey">列表Element的Key</param>
        /// <param name="iDrawFromUnity">是否从Unity调用绘制标志位</param>
        /// <param name="iOptions">选项</param>
        /// <param name="iOnChanged">变更回调</param>
        /// <returns>GUI绘制器 - 分页面板</returns>
        public static ISpPaginationDrawer Create(SerializedProperty iSelfProperty, 
            IPagination iPagination, string iElementKey, OnSearchBtnClicked iOnSearched = null, 
            bool iDrawFromUnity = false, int iOptions = (int)GUIOperateOptions.None, Action iOnChanged = null)
        {
            return new SpPaginationDrawer(iSelfProperty, iPagination, iElementKey, iOnSearched, iDrawFromUnity, iOptions, iOnChanged);
        }

#endregion

        /// <summary>
        /// 保护构造函数
        /// </summary>
        /// <param name="iSelfProperty">自身Property</param>
        /// <param name="iPagination">分页设定</param>
        /// <param name="iElementKey">列表Element的Key</param>
        /// <param name="iOnSearched">检索回调</param>
        /// <param name="iDrawFromUnity">是否从Unity调用绘制标志位</param>
        /// <param name="iOptions">选项</param>
        /// <param name="iOnChanged">变更回调</param>
        private SpPaginationDrawer(SerializedProperty iSelfProperty, 
            IPagination iPagination, string iElementKey, OnSearchBtnClicked iOnSearched = null, 
            bool iDrawFromUnity = false, int iOptions = (int)GUIOperateOptions.None, Action iOnChanged = null) : 
            base(iSelfProperty, iPagination, iOnSearched, iDrawFromUnity, iOptions)
        {
            ElementKey = iElementKey;
            PropertyChanged = iOnChanged;
        }
        
        /// <summary>
        /// 数组标志位
        /// </summary>
        public override bool IsArray => SelfProperty?.isArray ?? false;

        /// <summary>
        /// 总个数
        /// </summary>
        public override int TotalSize => IsArray ? (SelfProperty?.arraySize ?? 0) : 0;

        /// <summary>
        /// 列表Element的Key
        /// <para>* 用来排序，检索等用的Key</para>
        /// </summary>
        public string ElementKey { get; private set; } = null;

        protected Action PropertyChanged { get; private set; } = null;

#region Options

        /// <summary>
        /// 取得成员Element选项
        /// </summary>
        /// <returns>成员Element选项</returns>
        private int GetElementOptions()
        {
            var options = (int)GUIOperateOptions.DrawBg;
            if (MemberNoCaption)
            {
                options |= (int)GUIOperateOptions.MemberNoCaption;
            }
            
            if (MultiLine)
            {
                options |= (int)GUIOperateOptions.MultiLine;
            }

            return options;
        }

#endregion

#region Contents
        
        /// <summary>
        /// 取得Element标题
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <param name="iChildProperty">Child Property</param>
        /// <returns>Element标题</returns>
        protected override GUIContent GetElementCaption(int iIndex, SerializedProperty iChildProperty)
        {
            GUIContent caption = null;
            if (!ElementsCaptions.TryGetValue(iIndex, out caption))
            {
                if (!string.IsNullOrEmpty(ElementKey))
                {
                    var keyProperty = iChildProperty.FindPropertyRelative(ElementKey);
                    var captionTxtTmp = keyProperty.stringValue;
                    if (string.IsNullOrEmpty(captionTxtTmp))
                    {
                        caption = UtilsGUIEx.CreateGuiContent($"({iIndex})Element");
                    }
                    else
                    {
                        if (MemberAsset)
                        {
                            caption = UtilsGUIEx.CreateGuiContentByPathOfAsset(captionTxtTmp, captionTxtTmp, true);
                            caption.text = $"({iIndex}){caption.text}";

                        }
                        else
                        {
                            caption = UtilsGUIEx.CreateGuiContent($"({iIndex}){captionTxtTmp}");
                        }
                    }
                    ElementsCaptions.Add(iIndex, caption);
                }
                else
                {
                    caption = UtilsGUIEx.CreateGuiContent($"({iIndex})Element");
                    ElementsCaptions.Add(iIndex, caption);
                }
            }
            else
            {
                if (null == caption)
                {
                    caption = UtilsGUIEx.CreateGuiContent($"({iIndex})Element");
                }
                ElementsCaptions[iIndex] = caption;
            }
            
            return caption;
        }

#endregion

#region Controls

        /// <summary>
        /// 生成成员Element的HashCode
        /// </summary>
        /// <param name="iIndex">成员Element的索引</param>
        /// <param name="iTarget">目标成员</param>
        /// <returns>成员Element的HashCode</returns>
        protected override int GenerateElementHashCode(int iIndex, SerializedProperty iTarget)
        {
            var hashTxtDesc = $"{GetType().Name}_{iIndex}_{iTarget.propertyType}";
            return hashTxtDesc.GetHashCode();
        }

#endregion

#region Events
        
        /// <summary>
        /// 展开
        /// </summary>
        /// <param name="iChildProperty">Property</param>
        /// <param name="iIsExpanded">展开/缩进</param>
        private void ExpandChildrenOfChild(SerializedProperty iChildProperty, bool iIsExpanded)
        {
            if(null == iChildProperty) return;
            iChildProperty.isExpanded = iIsExpanded;
                    
            // 非数组元素
            var copy = iChildProperty.Copy();
            var end = copy.GetEndProperty();
                    
            var nextVisible = copy.NextVisible(true);
            while (nextVisible && !SerializedProperty.EqualContents(copy, end))
            {
                copy.isExpanded = iIsExpanded;
                nextVisible = copy.NextVisible(false);
            }
        }

#if UGUIEX_DEBUG
        public static bool TempFlg = false;
#endif

        /// <summary>
        /// 拖拽事件
        /// </summary>
        /// <param name="iAssets">拖拽的资产列表(如:文件/文件夹等)</param>
        protected override void OnAssetsDragAndDropDown(string[] iAssets)
        {
            if(null == iAssets || 0 >= iAssets.Length) return;

            var dirty = false;
            var count = iAssets.Length;
            for (var idx = 0; idx < count; ++idx)
            {
                var asset = iAssets[idx];
                if(string.IsNullOrEmpty(asset)) continue;

                var newProperty = AddNewElement(false);
                if (null == newProperty)
                {
                    Error("OnAssetsDragAndDropDown():AddNewElement() Failed!(Asset:{0})", asset);
                    continue;
                }

                var keyProperty = newProperty.FindPropertyRelative(ElementKey);
                if (null == keyProperty)
                {
                    Error("OnAssetsDragAndDropDown():Invalid Element!(There is no child property name {0})", ElementKey);
                    continue;
                }
                keyProperty.stringValue = asset;
                if (!dirty)
                {
                    dirty = true;
                }
            }

            if (dirty)
            {
                // 重置列表Element标题
                RefreshElementCaptions();
                ApplyChanged(SelfProperty);
#if UGUIEX_DEBUG
                TempFlg = true;
#endif
            }
        }
        
        /// <summary>
        /// 追加Element按钮点击时间
        /// </summary>
        protected override void OnAddElementBtnClicked()
        {
            if (!IsArray || null == SelfProperty) return;
            
            // 自增一个Element
            AddNewElement();
        }

        /// <summary>
        /// 追加新Element
        /// </summary>
        ///<param name="iDirty">脏字标志位(true:有变化; false:无变化;)</param>
        /// <returns>新的Element的Property</returns>
        private SerializedProperty AddNewElement(bool iDirty = true)
        {
            // 自增一个Element
            SelfProperty.arraySize++;
            if (1 < SelfProperty.arraySize)
            {
                SelfProperty.MoveArrayElement(SelfProperty.arraySize - 1, 0);
            }
            
            ListSelection.Select(0);

            if (iDirty)
            {
                // 重置列表Element标题
                RefreshElementCaptions();
                ApplyChanged(SelfProperty);
            }

            return SelfProperty.GetArrayElementAtIndex(0);
        }

        /// <summary>
        /// 删除Element按钮点击时间
        /// </summary>
        protected override void OnDelElementBtnClicked()
        {
            if (!IsArray || null == SelfProperty || 0 >= VisibleSize) return;

            var selectIndex = ListSelection.First;
            selectIndex = 0 >= selectIndex ? 0 : selectIndex;
            
            RemoveElementByIndex(selectIndex);
            ApplyChanged(SelfProperty);
        }

        /// <summary>
        /// 移除Element
        /// </summary>
        /// <param name="iIndex">索引</param>
        protected override void RemoveElementByIndex(int iIndex)
        {
            if(!IsArray || 0 >= VisibleSize || null == SelfProperty) return;
            
            // 检索中，则切换Property在总列表总的索引
            var targetIdx = iIndex;
            if (Searching)
            {
                var selectCapsule = SearchResult[iIndex];
                targetIdx = selectCapsule.Index;
            }
            
            if (targetIdx >= 0 && targetIdx < VisibleSize) 
            {
                var property = SelfProperty.GetArrayElementAtIndex(iIndex);
                if (property.propertyType == SerializedPropertyType.ObjectReference && property.objectReferenceValue) 
                {
                    property.objectReferenceValue = null;
                }
                
                SelfProperty.DeleteArrayElementAtIndex(targetIdx);
                ListSelection.Remove(iIndex);

                if (0 < VisibleSize) 
                {
                    ListSelection.Select(Mathf.Max(0, iIndex - 1));
                    // 若检索中
                    if (Searching)
                    {
                        SearchResult = DoSearchByKey(SearchKey);
                    }
                    PressIndex = ListSelection.First;
                }
            }
			
            // 重置列表Element标题
            RefreshElementCaptions();
        }
        
#endregion

#region Rect
        
        /// <summary>
        /// 取得Element高度
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <param name="iElement">Element</param>
        /// <returns>Element高度</returns>
        protected override float GetElementHeight(int iIndex, SerializedProperty iElement)
        {
            var elementHeight = GetPropertyHeight(iElement, GetElementCaption(iIndex, iElement), iElement.isExpanded);
            if (!iElement.isExpanded)
            {
                elementHeight += VerticalSpacing;
            }
            else
            {
                var visibleChildCount = iElement.GetVisibleChildCount();
                elementHeight += 1 == visibleChildCount ? 5 : 3;
            }

            //var expandedInfo = GetExpandedInfo(iElement);
            return elementHeight;
        }

        /// <summary>
        /// 计算子节点元素的总共高度
        /// </summary>
        /// <param name="iParent">父节点Property</param>
        /// <param name="oValidCount">有效个数</param>
        /// <returns>子节点元素的总共高度</returns>
        protected override float CalcElementsTotalHeight(SerializedProperty iParent, out int oValidCount)
        {
            oValidCount = 0;
            var elementTotalHeight = 0.0f;
            if (!IsArray || null == SelfProperty) return elementTotalHeight;

            if (0 >= VisibleSize)
            {
                elementTotalHeight = EmptyListHeight;
            }
            else
            {
                GetVisibleRange(VisibleSize, out var oStartIndex, out var oEndIndex);
                // 检索中
                if (Searching)
                {
                    for (var idx = oStartIndex; idx < oEndIndex; ++idx)
                    {
                        var childCapsule = SearchResult[idx];
                        elementTotalHeight += GetElementHeight(idx, childCapsule.Target) + 1;
                        ++oValidCount;
                    }
                }
                else
                {
                    for (var idx = oStartIndex; idx < oEndIndex; ++idx)
                    {
                        var childProperty = SelfProperty.GetArrayElementAtIndex(idx);
                        elementTotalHeight += GetElementHeight(idx, childProperty) + 1;
                        ++oValidCount;
                    }
                }
            }
            
            return elementTotalHeight;
        }
        
        /// <summary>
        /// 更新列表拖拽区域信息
        /// </summary>
        /// <param name="iDragPosition">拖拽坐标</param>
        /// <param name="iStartIndex">开始索引</param>
        /// <param name="iEndIndex">结束索引</param>
        protected override void UpdateListDragRects(float iDragPosition, int iStartIndex, int iEndIndex) 
        {
            if(null == SelfProperty) return;
            
            DragRectsList.Resize(iStartIndex, iEndIndex - iStartIndex);
            for (var i = iStartIndex; i < iEndIndex; ++i) 
            {
                var property = SelfProperty.GetArrayElementAtIndex(i);
                var elementRect = ElementRects[i];
                var dragElement = new DragElement
                {
                    Property = property,
                    DragOffset = DragPosition - elementRect.y,
                    Rect = elementRect,
                    DesiredRect = elementRect,
                    Selected = ListSelection.Contains(i),
                    StartIndex = i
                };
                DragRectsList[i - iStartIndex] = dragElement;
            }

            // 根据索引重排序
            DragRectsList.SortByIndex();
        }

#endregion

#region SerializedProperty

        /// <summary>
        /// 取得列表Element Property
        /// </summary>
        /// <param name="iIndex">索引</param>
        /// <returns>Element Property</returns>
        protected override SerializedProperty GetElementValue(int iIndex)
        {
            if (!IsArray) return null;

            var childCount = VisibleSize;
            if (0 > iIndex || iIndex >= childCount)
            {
                Error("GetElementValue():Invalid element index!(Index:{0}/{1})", iIndex, childCount);
                return null;
            }

            // 检索中
            if (Searching)
            {
                return SearchResult[iIndex].Target;
            }
            
            return SelfProperty.GetArrayElementAtIndex(iIndex);
        }

        /// <summary>
        /// 查找指定Element的索引
        /// </summary>
        /// <param name="iElement">Element</param>
        /// <returns>Element索引</returns>
        protected override int IndexOf(SerializedProperty iElement)
        {
            if (iElement == null || 0 >= VisibleSize) return -1;

            var targetIdx = -1;
            var idx = VisibleSize;
            while (--idx > -1)
            {
                var targetElement = Searching ? SearchResult[idx].Target : SelfProperty.GetArrayElementAtIndex(idx);
                if (SerializedProperty.EqualContents(iElement, targetElement))
                {
                    targetIdx = Searching ? SearchResult[idx].Index : idx;
                    break;
                }
            }

            return targetIdx;
        }

#endregion

#region Selections
        
        /// <summary>
        /// 选中变更事件
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <param name="iSelected">选中/没选中</param>
        protected override void OnSelectionChanged(int iIndex, bool iSelected)
        {
            SerializedProperty targetProperty = null;
                    
            if(0 > iIndex || iIndex >= VisibleSize) return;
            targetProperty = Searching ? SearchResult[iIndex].Target : SelfProperty.GetArrayElementAtIndex(iIndex);
			        
            if(null == targetProperty) return;
            ElementSelected?.Invoke(iIndex, targetProperty, iSelected);
        }

#endregion
        
#region Sort

        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="iAscending">true:升序; false:倒序;</param>
        public override void Sort(bool iAscending)
        {
            if(!IsArray || 0 >= VisibleSize) return;
                    
            // 排序
            PropertyArraySort.SortOnProperty(SelfProperty, VisibleSize, !iAscending, ElementKey);
            
            // 应用
            ApplyChanged(SelfProperty);
            // 刷新标题
            RefreshElementCaptions();
            
            HandleUtility.Repaint();
        }

        /// <summary>
        /// 应用排序
        /// </summary>
        protected override void ApplyReorder() => ApplyChanged(SelfProperty);
        
        /// <summary>
        /// 应用改变
        /// </summary>
        private void ApplyChanged(SerializedProperty iProperty) 
        {
            if(null == iProperty) return;
            iProperty.serializedObject.ApplyModifiedProperties();
            iProperty.serializedObject.Update();
            
            PropertyChanged?.Invoke();
        }

#endregion

#region SearchBar
        
        /// <summary>
        /// 执行检索
        /// </summary>
        /// <param name="iSearchKey">检索Key</param>
        protected override List<SearchCapsule<SerializedProperty>> DoSearchByKey(string iSearchKey)
        {
            if (string.IsNullOrEmpty(ElementKey) || !IsArray || 0 >= TotalSize) return null;

            if (string.IsNullOrEmpty(iSearchKey))
            {
                Searching = false;
                return null;
            }
            
            var searchResult = new List<SearchCapsule<SerializedProperty>>();
            var count = TotalSize;
            for (var idx = 0; idx < count; idx++)
            {
                var childProperty = SelfProperty.GetArrayElementAtIndex(idx);
                var keyProperty = childProperty?.FindPropertyRelative(ElementKey);
                if(keyProperty == null) continue;

                var keyValue = keyProperty.stringValue;
                if(string.IsNullOrEmpty(keyValue)) continue;

                if (!keyValue.ToLower().Contains(iSearchKey.ToLower())) continue;
                var searchCapsule = new SearchCapsule<SerializedProperty> { Index = idx, Target = childProperty };
                searchResult.Add(searchCapsule);
            }
            
            return searchResult;
        }

#endregion

#region Draw

        /// <summary>
        /// 绘制Element列表
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制范围</returns>
        protected override Rect DrawElements(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;
            
            if (!Dragging) 
            {
                UpdateElementRects(displayRect, iEvent);
            }
            if (0 >= ElementRects.Length) return displayRect;
            if (!GetVisibleRange(out var oStartIndex, out var oEndIndex)) return displayRect;
                            
            var selectableRect = displayRect;
            selectableRect.yMin = ElementRects[oStartIndex].yMin;
            selectableRect.yMax = ElementRects[oEndIndex - 1].yMax;
                            
            HandlePreSelection(selectableRect, iEvent);
            var lastEnable = GUI.enabled;
            GUI.enabled = !ReadOnly;

            if (Searching)
            {
                for (var idx = oStartIndex; idx < oEndIndex; ++idx)
                {
                    var childCapsule = SearchResult[idx];
                    var elementCaption = GetElementCaption(idx, childCapsule.Target);
                    if(null == elementCaption) continue;

                    var childRect = ElementRects[idx];
                    var selected = ListSelection.Contains(idx);
                    //if(3 == idx && childProperty.isExpanded) continue;
                
                    childRect = DrawElement(childRect, iEvent, childCapsule.Target, idx, elementCaption, selected, selected);
                    childRect.y = childRect.yMax;
                }
            }
            else
            {
                for (var idx = oStartIndex; idx < oEndIndex; ++idx)
                {
                    var childProperty = SelfProperty.GetArrayElementAtIndex(idx);
                    if(null == childProperty) continue;

                    var elementCaption = GetElementCaption(idx, childProperty);
                    if(null == elementCaption) continue;

                    var childRect = ElementRects[idx];
                    var selected = ListSelection.Contains(idx);
                    //if(3 == idx && childProperty.isExpanded) continue;
                
                    childRect = DrawElement(childRect, iEvent, childProperty, idx, elementCaption, selected, selected);
                    childRect.y = childRect.yMax;
                }
            }
                            
            GUI.enabled = lastEnable;
            HandlePostSelection(selectableRect, iEvent);
                            
            return displayRect;
        }
        
        /// <summary>
        /// 绘制Element
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iElement">Element Property</param>
        /// <param name="iElementIndex">Element索引</param>
        /// <param name="iCaption">标题</param>
        /// <param name="iSelected">选中标志位</param>
        /// <param name="iFocused">焦点</param>
        /// <returns>绘制范围</returns>
        private Rect DrawElement(Rect iRect, Event iEvent, SerializedProperty iElement, int iElementIndex, 
            GUIContent iCaption, bool iSelected, bool iFocused)
        {
            var displayRect = iRect;
            
            // 可选中背景
            var bgRect = displayRect;
            var selectBgRect = displayRect;
            selectBgRect.yMax += 2;
            selectBgRect = UtilsGUIEx.DrawListElementBg(selectBgRect, iEvent, iSelected, iFocused);
            
            var dragMarkRect = displayRect;
            dragMarkRect.y = displayRect.yMin + VerticalSpacing;
            dragMarkRect.width = DragMarkWidth;
            dragMarkRect = UtilsGUIEx.DrawDragMark(dragMarkRect, iEvent);

            var captionRect = bgRect;
            captionRect.xMin = dragMarkRect.xMax + HorizontalSpacing;
            captionRect.xMin += HorizontalSpacing;
            captionRect.xMax -= 1;
            captionRect.y += 1;
            captionRect.height = HeaderHeight;
            if (iElement.hasVisibleChildren)
            {
                
                captionRect = DrawGenericBg(captionRect, iEvent);
                
                // 锁定
                var maxBtnRect = captionRect;
                var isElementLocked = IsElementLocked(iElementIndex);
                var maxPosX = captionRect.xMax;
                if (Lockable)
                {
                    var lockBtnRect = captionRect;
                    lockBtnRect.xMax = captionRect.xMax - HorizontalSpacing - 1;
                    lockBtnRect.xMin = lockBtnRect.xMax - BtnWidthIconOnly;
                    maxBtnRect.xMax = lockBtnRect.xMin - 1;
                    if (isElementLocked)
                    {
                        if (GUI.Button(lockBtnRect, LockIconBtnContent, GuiExHelper.PreButtonStretch))
                        {
                            SetElementLockState(iElementIndex, false);
                        }
                    }
                    else
                    {
                        if (GUI.Button(lockBtnRect, UnLockIconBtnContent, GuiExHelper.PreButtonStretch))
                        {
                            SetElementLockState(iElementIndex, true);
                        }
                    }
                    maxPosX = lockBtnRect.xMax;
                }
                
                // 最大化
                maxBtnRect.xMin = maxBtnRect.xMax - BtnWidthIconOnly;
                if (GUI.Button(maxBtnRect, GuiExHelper.MaxWinBtn, GuiExHelper.PreButtonStretch)) 
                {
                    ExpandChildrenOfChild(iElement, true);
                }
                
                var minBtnRect = maxBtnRect;
                minBtnRect.xMax = maxBtnRect.xMin - 1;
                minBtnRect.xMin = minBtnRect.xMax - BtnWidthIconOnly;
            
                // 不展开按钮 - 右上角最小化按钮
                if (GUI.Button(minBtnRect, GuiExHelper.MinWinBtn, GuiExHelper.PreButtonStretch)) 
                {
                    ExpandChildrenOfChild(iElement, false);
                }

                var deltaWidth = (minBtnRect.xMin - HorizontalSpacing) - (maxPosX + HorizontalSpacing);
                captionRect = UtilsGUIEx.DrawFoldout(captionRect, iEvent, iElement, iCaption, null,false, 
                    (int)GUIOperateOptions.FoldoutNoBg, deltaWidth);
                
                // 展开
                if (iElement.isExpanded)
                {
                    var childBodyBgRect = bgRect;
                    childBodyBgRect.xMin = captionRect.xMin;
                    childBodyBgRect.xMax = captionRect.xMax;
                    childBodyBgRect.yMin = captionRect.yMax - 1;
                    //childBodyBgRect.yMax -= 1;
                    childBodyBgRect = UtilsGUIEx.DrawGenericBg(childBodyBgRect, iEvent);
                    
                    var childDragMarkRect = childBodyBgRect;
                    childDragMarkRect.y = childBodyBgRect.yMin + VerticalSpacing;
                    childDragMarkRect.width = DragMarkWidth;
                    childDragMarkRect.height = SingleLineHeight;
                    childDragMarkRect = UtilsGUIEx.DrawDragMark(childDragMarkRect, iEvent);
                    
                    // 非数组元素
                    var copy = iElement.Copy();
                    var end = copy.GetEndProperty();
                    
                    var childChildRect = childBodyBgRect;
                    childChildRect.xMin = childDragMarkRect.xMax + VerticalSpacing;
                    childChildRect.xMax -= HorizontalSpacing;
                    childChildRect.yMin += VerticalSpacing;
                    childChildRect.height = SingleLineHeight;

                    var editable = true;
                    var lastEnable = GUI.enabled;
                    if (Lockable)
                    {
                        editable = !ReadOnly && !isElementLocked;
                        GUI.enabled = editable;
                    }
                    
                    var nextVisible = copy.NextVisible(true);
                    while (nextVisible && !SerializedProperty.EqualContents(copy, end)) 
                    {
                        //if (copy.hasVisibleChildren)
                        {
                            var copyHeight = EditorGUI.GetPropertyHeight(copy);
                            childChildRect.height = copyHeight;
                            childChildRect = UtilsGUIEx.DrawProperty(childChildRect, iEvent, copy, 
                                null, null, (int)GUIOperateOptions.DrawBg);
                            childChildRect.y = childChildRect.yMax + 1;
                        }
                        nextVisible = copy.NextVisible(false);
                    }

                    if (Lockable)
                    {
                        GUI.enabled = lastEnable;
                    }
                }
            }
            else
            {
                var editable = true;
                var lastEnable = GUI.enabled;
                var isElementLocked = IsElementLocked(iElementIndex);
                if (Lockable)
                {
                    editable = !ReadOnly && !isElementLocked;
                    GUI.enabled = editable;
                }
                
                var elementOptions = GetElementOptions();
                var elementCaption = MemberNoCaption ? null : iCaption;
                captionRect = UtilsGUIEx.DrawProperty(captionRect, iEvent, iElement, elementCaption,
                    ApplyChanged, elementOptions);

                if (Lockable)
                {
                    GUI.enabled = lastEnable;
                }
            }
            
            return displayRect;
        }

#endregion
        
    }
}
